#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include "Log.hpp"
#include "Thread.hpp"
#include "Cond.hpp"
#include "Mutex.hpp"

namespace ThreadPoolModule
{
    using namespace ThreadModlue;
    using namespace LogModule;
    using namespace CondModule;
    using namespace Mutex_Model;
    static const int gnums = 5;

    template <typename T>
    class ThreadPool
    {
    private:
        // 线程池创建(本质是创建并存储线程)
        ThreadPool(int nums = gnums)
            : _nums(nums), _is_running(true), _c_sleep(0)
        {
            // 创建线程
            for (int i = 0; i < _nums; i++)
            {
                _thread_pool.emplace_back([this]()
                                          { Handler(); });
            }
        }

        // 启动线程
        void Start()
        {
            for (auto &thread : _thread_pool)
            {
                thread.Start();
                LOG(INFO) << "start new thread success: " << thread.Name();
            }
        }

        // 唤醒所有线程
        void WakeUpAllThread()
        {
            Mutex_Gurda Lock(&_mutex);
            if (_c_sleep)
                _cond.Broadcast();
        }

        // 唤醒一个线程
        void WakeUpOne()
        {
            _cond.Signal();
            LOG(INFO) << "唤醒一个休眠线程-> ";
        }

    public:
        // 获取单例
        static ThreadPool<T> *GetInstance()
        {
            // 如果静态指针为空创建 不为空则返回
            if (_inc == nullptr)
            {
                Mutex_Gurda lock(&_lock); // 加锁
                _inc = new ThreadPool<T>();
                _inc->Start();
            }

            return _inc;
        }

        // 线程池退出
        void Stop()
        {
            if (!_is_running)
                return;

            _is_running = false;

            // 线程唤醒
            if (_c_sleep)
            {
                LOG(DEBUG) << "当前休眠的线程有 " << _c_sleep << "个,将其全部唤醒, 线程池准备退出";
                WakeUpAllThread();
            }
        }

        // 线程等待
        void Join()
        {
            if (!_is_running)
            {
                for (auto &thread : _thread_pool)
                {
                    thread.Join();
                }
            }
        }
        // 任务处理函数
        void Handler()
        {
            // 获取线程名
            char name[128];
            pthread_getname_np(pthread_self(), name, sizeof(name));
            // 处理任务
            while (true)
            {
                T t;
                {
                    // 加锁
                    Mutex_Gurda Lock(&_mutex);

                    // 线程休眠 a. 队列为空 b. is_running = true
                    while (_taskq.empty() && _is_running)
                    {
                        _c_sleep++;
                        _cond.Wait(_mutex);
                        _c_sleep--;

                        LOG(INFO) << "[" << name << "] 被唤醒";
                    }

                    // 线程退出  a. 队列为空  b. is_running = fasle
                    if (_taskq.empty() && !_is_running)
                    {
                        LOG(INFO) << "[" << name << "]" << "-> " << "退出成功, 线程池退出&&任务队列为空";
                        break;
                    }

                    // 获取任务 a. 队列非空 && is_running = true b.  队列非空 && is_running = false
                    t = _taskq.front();
                    _taskq.pop();
                }

                // 执行任务
                t();
            }
        }

        // 任务插入函数
        bool Equeue(const T &in)
        {
            // 线程正常运行 才插入任务
            if (_is_running)
            {
                // 加锁
                Mutex_Gurda Lock(&_mutex);
                _taskq.push(in);

                // 唤醒一个线程处理当前任务
                if (_c_sleep == _nums) // 如果所有线程均在休眠
                    WakeUpOne();

                return true;
            }
            return false;
        }

        ~ThreadPool() {}

    private:
        std::vector<Thread> _thread_pool; // 线程池
        int _nums;                        // 线程个数
        std::queue<T> _taskq;             // 任务队列
        Mutex _mutex;                     // 互斥锁
        Cond _cond;                       // 条件变量
        bool _is_running;                 // 线程池转状态变量
        int _c_sleep;                     // 休眠线程的数量

        static ThreadPool<T> *_inc; // 单例静态指针
        static Mutex _lock;         // 单例锁
    };
    template <typename T>
    ThreadPool<T> *ThreadPool<T>::_inc = nullptr;
    template <typename T>
    Mutex ThreadPool<T>::_lock;
}